//
//  Data Structures Tutorial
//
//  Copyright 2014 by Balamurugan Souppourayen <srimuruganbala@gmail.com>
//
//  Licensed under GNU General Public License 3.0 or later.
//  Some rights reserved. See COPYING, AUTHORS.
//
//  @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>
//

#include "TLinkedList.h"
#include <cassert>
#include <cstdio>

TLinkedList::TNode::TNode(int32_t data, TLinkedList::TNode* next)
: Data(data),
  Next(next)
{
  // Empty
}

TLinkedList::TLinkedList()
:   Header(NULL),
    ListSize(0)
{
  // Empty
}

TLinkedList::~TLinkedList()
{
  Clear();
}

TLinkedList::TNode& TLinkedList::Goto(size_t index)
{
  assert(index < ListSize);
  TNode* temp = Header;
  for (size_t i = 0; i < ListSize; ++i) {
    if (i == index) {
      break;
    }
    temp = temp->Next;
  }
  return *temp;
}

int32_t TLinkedList::operator[](size_t index)
{
  return Goto(index).Data;
}

size_t TLinkedList::Size()
{
  return ListSize;
}

void TLinkedList::PushFront(int32_t data)
{
  Insert(0, data);
}

size_t TLinkedList::PushBack(int32_t data)
{
  TNode* newNode = new TNode(data, NULL);
  if (Header == NULL) {
    Header = newNode;
  }
  else {
    Goto(ListSize-1).Next = newNode;
  }

  ++ListSize;
  return ListSize - 1;
}

void TLinkedList::Insert(size_t index, int32_t data)
{
  assert(index < ListSize);
    
  TNode* newNode = new TNode(data, NULL);
  if (index == 0) {
    newNode->Next = Header;
    Header = newNode;
  }
  else {
    TNode& currentNode = Goto(index);
    TNode& prevNode = Goto(index - 1);
    prevNode.Next = newNode;
    newNode->Next = &currentNode;
  }
  ++ListSize;
}

void TLinkedList::Delete(size_t index)
{
  assert(index < ListSize);

  TNode& currentNode = Goto(index);
  if (index == 0) {
    Header = currentNode.Next;
  }
  else {
    TNode& prevNode = Goto(index -1);
    prevNode.Next = currentNode.Next;

  }

  delete &currentNode;
  --ListSize;
}

void TLinkedList::Clear()
{
  while (ListSize > 0) {
    Delete(0);
  }
}

void TLinkedList::PrintList()
{
    TNode* node = Header;
    ::printf("Header->%p\n", Header);
    for (size_t i = 0; i < ListSize; ++i) {
        ::printf("[%lu] Data=%d | Next->%p\n", i, node->Data, node->Next);
        node = node->Next;
    }
}
